/**
 * Copyright [2015] Tianfu Ma (matianfu@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * File: buddy.c
 *
 * Created on: Jun 5, 2015
 * Author: Tianfu Ma (matianfu@gmail.com)
 */

#include "../include/errno.h"
#include "../include/data_type.h"
#include "../include/alloc.h"
#include "../include/string.h"
#include "alloc_init.h"
#include "cube_dynamic.h"
#include "alloc_struct.h"
//int dmem_upper_defaultfresh(void * pointer);
//int dmem_lower_defaultfresh(void * pointer);

//int (*dmem_upper_fresh[16])(void * );
//int (*dmem_lower_fresh[16])(void * );

#define DPOINTER_EMPTY 0xffffffff

static struct dmem_sys * dmem_struct;
extern struct page_index *pages;
extern BYTE * first_page;
extern struct alloc_total_struct * root_struct;
int  dynamic_init ()
{
	void *  ret;
	UINT16 start_page;

	ret=get_firstpagemem_bottom(sizeof(struct dmem_sys));
	if(ret==NULL)
		return 	-CUBEERR_NOMEM;
	dmem_struct = (struct dmem_sys *)ret;
	Memset(dmem_struct,0,sizeof(*dmem_struct));
	start_page=get_page();
	if(start_page==0)
		return 0;
	root_struct -> occupy_size ++;
	root_struct -> empty_pages --;
	pages[start_page].type = DYNAMIC_PAGE;
	dmem_struct->total_size=PAGE_SIZE;	
	dmem_struct->pages_num++;	
	dmem_struct->first_page=start_page;
	dmem_struct->curr_page=start_page;

	return (void *)dmem_struct - page_get_addr(0);

}

void * Dalloc(int size,void * parent)
{

	void * addr;
	UINT16 page;
	int real_size;
	real_size=size+5*sizeof(UINT16);
	if(real_size>PAGE_SIZE)
		return 0;
	if(PAGE_SIZE - dmem_struct->curr_offset > real_size)
	{
		addr = first_page + dmem_struct->curr_page*PAGE_SIZE +dmem_struct->curr_offset+5*sizeof(UINT16);
		dmem_struct->curr_offset += real_size;
		dmem_struct->total_size += real_size;
	}
	else{
		page=get_page();
		if(page == 0)
			return 0;
		root_struct -> occupy_size ++;
		root_struct -> empty_pages --;
		pages[page].type = DYNAMIC_PAGE;
		pages[page].priv_page = dmem_struct->curr_page;
		pages[dmem_struct->curr_page].next_page = page;
		pages[page].type = DYNAMIC_PAGE;
		dmem_struct->curr_page = page;
		dmem_struct->pages_num++;
		addr = first_page+page*PAGE_SIZE+5*sizeof(UINT16);
		dmem_struct->curr_offset = real_size;
	}
	*(UINT16 *)(addr-sizeof(UINT16))=size;
	if(parent != NULL)
		*(UINT16 *)(addr-5*sizeof(UINT16)) = parent;
	/* 	
   		Memset(elem_head,0,sizeof(*object_head));
		elem_head->pointer_addr=NULL;
		addr+=sizeof(*elem_head); 
		DMEM_SET_SIZE(get_cube_pointer(addr),size-sizeof(*elem_head));
		DMEM_SET_FLAG(get_cube_pointer(addr),CUBE_DMEM_ELEM);
		pages[page].state += size;
		dmem_struct->total_size += size;		
	*/	
	return addr;
}

void * Dpointer_set(void * pointer,void * base)
{
    if(base!=NULL)
        *(void **)base=pointer;

    *(void **)(pointer-sizeof(UINT16)-sizeof(void *))=base;
    return pointer;
}

int DFree(void * pointer)
{
        *(void **)(pointer-sizeof(UINT16)-sizeof(void *))=DPOINTER_EMPTY;
 //       free(pointer-sizeof(UINT16)-sizeof(void *));
        return 0;
}


/*
UINT32 Dfree(UINT32 addr)
{
	UINT16 size;
	BYTE flag;
	UINT16 page;

	struct dmem_object_head * object_head;
	struct dmem_head * elem_head;

	size=DMEM_GET_SIZE(addr);
	flag=DMEM_GET_FLAG(addr);
	page=addr_get_page(addr);
	switch(flag)
	{
		case CUBE_DMEM_EMPTY:
		case CUBE_DMEM_ZOMBIE:
			return 0;
		case CUBE_DMEM_ELEM:
			size+=sizeof(*elem_head);
			elem_head=(struct dmem_elem_head *)((BYTE *)addr -sizeof(*elem_head));
			DMEM_SET_FLAG(get_cube_pointer(addr),CUBE_DMEM_ZOMBIE);
			elem_head->pointer_addr=NULL;
			pages[page].state-=size;
			dmem_struct->total_size-=size;		
			break;
		case CUBE_DMEM_OBJECT:
			size+=sizeof(*object_head);
			object_head=(struct dmem_object_head *)((BYTE *)addr -sizeof(*object_head));
			DMEM_SET_FLAG(get_cube_pointer(addr),CUBE_DMEM_ZOMBIE);
			object_head->pointer_addr=NULL;
			pages[page].state-=size;
			dmem_struct->total_size-=size;		
			break;
	}
	return size;	
}
*/
